/*  GMooc - A Java web application for delivering massive open online courses
*   Copyright (C) 2012 Charles A. Wight
*   
*    This program is free software: you can redistribute it and/or modify
*   it under the terms of the GNU General Public License as published by
*   the Free Software Foundation, either version 3 of the License, or
*   (at your option) any later version.
*
*   This program is distributed in the hope that it will be useful,
*   but WITHOUT ANY WARRANTY; without even the implied warranty of
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*   GNU General Public License for more details.
*
*   You should have received a copy of the GNU General Public License
*   along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

package org.gmooc;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collections;
import java.util.List;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.googlecode.objectify.Objectify;

@SuppressWarnings("serial")
public class Admin extends HttpServlet {
	
	Objectify ofy = new DAO().ofy();
	
	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws IOException {
		User user = (User)request.getSession(true).getAttribute("User");
		if (user==null) response.sendRedirect("/");  // stale web session
		// the web.xml file lists this servlet with a security-constraint so that it is
		// accessible only to those with admin privileges in the gmooc-hrd application
		if (!user.isAdministrator()) {
			user.setIsAdministrator(true);
			ofy.put(user);
			request.getSession().setAttribute("User",user);
		}
		
		response.setContentType("text/html");
		PrintWriter out = response.getWriter();
		if ("Edit User".equals(request.getParameter("UserRequest"))) out.println(userProfileForm(user,request));
		else if ("Edit Course".equals(request.getParameter("UserRequest"))) out.println(courseProfileForm(user,request));
		else out.println(mainAdminPage(user,request));
	}
	
	public void doPost(HttpServletRequest request, HttpServletResponse response)
	throws IOException {
		User user = (User)request.getSession(true).getAttribute("User");
		if (user==null) response.sendRedirect("/");
		if (!user.isAdministrator()) {
			user.setIsAdministrator(true);
			ofy.put(user);
		}
		String userRequest = request.getParameter("UserRequest");
		response.setContentType("text/html");
		PrintWriter out = response.getWriter();

		if ("Cancel".equals(userRequest)) {
			doGet(request,response);
			return;
		} else if ("Submit User Changes".equals(userRequest)) {
			User u = ofy.find(User.class,request.getParameter("UserId"));
			updateUserProfile(u,request);
			out.println(userProfilePage(user,u));
		} else if ("Delete User".equals(userRequest)) {
			User u = ofy.find(User.class,request.getParameter("UserId"));
			if (u!=null) ofy.delete(u);
			out.println(mainAdminPage(user,request));
		} else if ("Create A New Course".equals(userRequest)) {
			ofy.put(new Course("New Course",user));
			out.println(mainAdminPage(user,request));
		} else if ("Submit Course Changes".equals(userRequest)) {
			Course c = ofy.find(Course.class,request.getParameter("CourseId"));
			updateCourseProfile(c,request);
			out.println(courseProfilePage(user,c));
		} else out.println(mainAdminPage(user,request));
	}
	
	private String mainAdminPage(User user, HttpServletRequest request) {
		StringBuffer buf = new StringBuffer(Home.header(user));
		buf.append("<h2>Admin Page</h2>");
		buf.append("Use this page to manage users and courses.");
		
		buf.append("<h3>Users</h3>");
		// clean up the user email search string a bit, if it exists:
		String searchString = request.getParameter("SearchString");
		if (searchString==null) searchString=""; // avoids null pointer errors later
		else searchString = searchString.toLowerCase().trim();  // all email addresses are lowercase
		
		buf.append("<form method=get action=/admin>Search for a user by email address: "
				+ "<input type=text name=SearchString value='" + searchString.replaceAll("'","&#39;") + "'>"
				+ "<input type=submit name=UserRequest value='Search'></form><p>");
		
		if (searchString.length()>0 || "Search".equals(request.getParameter("UserRequest"))) {  // show the results of the user search
			try {
				buf.append("<h3>Search Results</h3>");
				List<User> searchResults = ofy.query(User.class).filter("email >=",searchString).filter("email <",(searchString+'\ufffd')).limit(20).list();
				int n = searchResults.size();
				if (n==0) buf.append("There are no users matching this email address.");
				else {
					buf.append((n==20?"More than ":"") + n + " users found:<br>");
					buf.append("<table>");
					for (User u : searchResults) {
						buf.append("<tr><td>" + u.getFullName() + "</td><td>" + u.getEmail() 
								+ "</td><form method=get action=admin><td><input type=hidden name=UserId value='" 
								+ u.getId() + "'><input type=submit name=UserRequest value=Edit></form></td></tr>");
					}
					buf.append("</table>");
				}
			} catch (Exception e) { // invalid search string = no results
			}
		}

		buf.append("<h3>Courses</h3>");
		List<Course> courses = ofy.query(Course.class).list();
		if (courses.size()==0) buf.append("There are no courses yet.");
		else {
			Collections.sort(courses);
			buf.append("<table><tr><td>Title</td><td>Instructor</td><td>Start Date</td><td>Published</td></tr>");
			for (Course c : courses) buf.append("<tr><td>" + c.getTitle() + "</td><td>" + c.getInstructor().getFullName() 
					+ "</td><td style='text-align:center'>" + c.getStartDate() + "</td><td style='text-align:center'>" + (c.getPublished()?"yes":"no") 
					+ "</td><form method=get action=admin><td><input type=hidden name=CourseId value=" +c.getId() + "><input type=submit name=UserRequest value='Edit Course'></td></tr>");
			buf.append("</table>");
		}
		buf.append("<form method=post action=admin><input type=submit name=UserRequest value='Create A New Course'></form>");

		return buf.toString() + Home.footer;		
	}

	String userProfileForm(User user,HttpServletRequest request) {
			return userProfileForm(user,ofy.find(User.class,request.getParameter("UserId")),request);
	}
	
	String userProfileForm(User user,User u,HttpServletRequest request) {
		StringBuffer buf = new StringBuffer(Home.header(user));
		if (u==null) return "Sorry, we could not locate this user record.";
		buf.append("<h2>Edit User</h2>"
				+ "<form method=post action=admin><table>"
				+ "<input type=hidden name=UserId value='" + u.getId() + "'>"
				+ "<input type=hidden name=SearchString value='" + u.getEmail() + "'>"
				+ "<tr><td style='text-align:right'>UserId: </td><td>" + u.getId() + "</td></tr>"
				+ "<tr><td style='text-align:right'>Last Logged In:</td><td>" + u.getLastLogin() + (u.needsNewTermsAgreement()?" (needs new Terms agreement)":"") + "</td></tr>"
				+ "<tr><td style='text-align:right'>First Name: </td><td><input type=text name=FirstName value='" + u.getFirstName() + "'></td></tr>"
				+ "<tr><td style='text-align:right'>Last Name: </td><td><input type=text name=LastName value='" + u.getLastName() + "'></td></tr>"
				+ "<tr><td style='text-align:right'><input type=checkbox name=MakeAnonymous value=true" + (u.isAnonymous()?" CHECKED":"") + "></td><td>Don't display name publicly</td></tr>"
				+ "<tr><td style='text-align:right'>Email: </td><td><input type=text name=Email value='" + u.getEmail() + "'></td></tr>"
				+ "<tr><td style='text-align:right;vertical-align:top'>Roles:</td><td>"
				+ "<input type=checkbox name=Roles value=1" + (u.isStudent()?" CHECKED":"") + ">Student<br>"
				+ "<input type=checkbox name=Roles value=2" + (u.isContributor()?" CHECKED":"") + ">Contributor<br>"
				+ "<input type=checkbox name=Roles value=4" + (u.isEditor()?" CHECKED":"") + ">Editor<br>"
				+ "<input type=checkbox name=Roles value=8" + (u.isTeachingAssistant()?" CHECKED":"") + ">Teaching Assistant<br>"
				+ "<input type=checkbox name=Roles value=16" + (u.isInstructor()?" CHECKED":"") + ">Instructor<br>"
				+ "<input type=checkbox name=Roles value=32" + (u.isAdministrator()?" CHECKED":"") + ">Administrator<br></td></tr>"
				+ "<tr><td></td><td><input type=submit name=UserRequest value='Submit User Changes'><input type=submit name=UserRequest value=Cancel>"
				+ "<input type=submit name=UserRequest value='Delete User' onClick=\"return confirm('Delete this user. Are you sure?')\"></td></tr>"
				+ "</table></form>");
		return buf.toString() + Home.footer;
	}
	
	private void updateUserProfile(User u,HttpServletRequest request) {
		try {
			u.setFirstName(request.getParameter("FirstName"));
			u.setLastName(request.getParameter("LastName"));
			boolean anonymous = Boolean.parseBoolean(request.getParameter("MakeAnonymous")); // user preference
			u.setAnonymous(anonymous);
			String[] roleArray = request.getParameterValues("Roles");
			int roles = 0;
			if (roleArray==null) roles = -1;
			else for (String r : roleArray) roles += Integer.parseInt(r);
			u.setRoles(roles);
			ofy.put(u);
		} catch (Exception e) {}
	}
	
	private String userProfilePage(User user,User u) {
		StringBuffer buf = new StringBuffer(Home.header(user));
		buf.append("<h2>User Profile</h2>"
				+ "<table>"
				+ "<form method=get action=admin>"
				+ "<input type=hidden name=UserId value='" + u.getId() + "'>"
				+ "<tr><td style='text-align:right'>UserId:</td><td>" + u.getId() + "</td></tr>"
				+ "<tr><td style='text-align:right'>Last Logged In:</td><td>" + u.getLastLogin() + (u.needsNewTermsAgreement()?" (needs new Terms agreement)":"") + "</td></tr>"
				+ "<tr><td style='text-align:right'>First Name:</td><td>" + u.getFirstName() + "</td></tr>"
				+ "<tr><td style='text-align:right'>Last Name:</td><td>" + u.getLastName() + "</td></tr>"
				+ "<tr><td colspan=2>Public forums will show this user as <i>" + u.getPublicName() + "</i>.</td></tr>"
				+ "<tr><td style='text-align:right'>Email:</td><td>" + u.getEmail() + "</td></tr>"
				+ "<tr><td style='text-align:right;vertical-align:top'>Roles:</td><td>" 
				+ (u.isDeactivated()?"<span style='color:red'>Deactivated</span>":(u.isStudent()?"Student":"") + (u.isContributor()?"<br>Contributor":"")
				+ (u.isEditor()?"<br>Editor":"") + (u.isTeachingAssistant()?"<br>Teaching Assistant":"") 
				+ (u.isInstructor()?"<br>Instructor":"") + (u.isAdministrator()?"<br>Administrator":"")) + "</td></tr>"
				+ "<tr><td></td><td><input type=submit name=UserRequest value='Edit User'></td></tr>"
				+ "</form>"
				+ "</table>");
		return buf.toString() + Home.footer;
	}
	String courseProfileForm(User user,HttpServletRequest request) {
		StringBuffer buf = new StringBuffer(Home.header(user));
		try {
			Course c = ofy.get(Course.class,Long.parseLong(request.getParameter("CourseId")));
			buf.append("<h2>Edit Course</h2>"
					+ "<form method=post action=admin><table>"
					+ "<input type=hidden name=CourseId value='" + c.getId() + "'>"
					+ "<tr><td style='text-align:right'>CourseId: </td><td>" + c.getId() + "</td></tr>"
					+ "<tr><td style='text-align:right'>Title: </td><td><input type=text name=Title value='" + c.getTitle() + "'></td></tr>");
			for (String id : c.instructorIds) buf.append("<tr><td style='text-align:right'><input type=checkbox name=DeleteInstructor value='" + id + "'>Delete Instructor: </td><td>" + User.getPublicName(id) + "</td></tr>");		
			buf.append("<tr><td style='text-align:right'>Start Date: </td><td><input type=text name=StartDate value='" + c.getStartDate() + "'></td></tr>"
					+ "<tr><td style='text-align:right'>End Date: </td><td><input type=text name=EndDate value='" + c.getEndDate() + "'></td></tr>"
					+ "<tr><td style='text-align:right'>Published: </td><td><input type=checkbox name=Published value=true" + (c.getPublished()?" CHECKED>":">")  + "</td></tr>"
					+ "<tr><td></td><td><input type=submit name=UserRequest value='Submit Course Changes'></td></tr>"
					+ "</table></form>");
		} catch (Exception e) {
			buf.append("An unexpected error occurred.");
		}
		return buf.toString() + Home.footer;
	}
	
	void updateCourseProfile(Course c,HttpServletRequest request) {
		try {
			c.setTitle(request.getParameter("Title"));
			String[] deleteInstructors = request.getParameterValues("DeleteInstructor");
			for (String id : deleteInstructors) c.removeInstructor(User.getInstance(id));
			c.setStart(request.getParameter("StartDate"));
			c.setEnd(request.getParameter("EndDate"));
			c.setPublished(Boolean.parseBoolean(request.getParameter("Published")));
			ofy.put(c);
		} catch (Exception e) {}
	}

	private String courseProfilePage(User user,Course c) {
		StringBuffer buf = new StringBuffer(Home.header(user));
		buf.append("<h2>Course Profile</h2>"
				+ "<table>"
				+ "<form method=get action=admin>"
				+ "<input type=hidden name=CourseId value='" + c.getId() + "'>"
				+ "<tr><td style='text-align:right'>CourseId:</td><td>" + c.getId() + "</td></tr>"
				+ "<tr><td style='text-align:right'>Title:</td><td>" + c.getTitle() + "</td></tr>");
		for (String id : c.instructorIds) buf.append("<tr><td style='text-align:right'>Instructor:</td><td>" + User.getPublicName(id) + "</td></tr>");
		buf.append("<tr><td style='text-align:right'>Start Date:</td><td>" + c.getStartDate() + "</td></tr>"
				+ "<tr><td style='text-align:right'>End Date:</td><td>" + c.getEndDate() + "</td></tr>"
				+ "<tr><td style='text-align:right'>Published:</td><td><input type=checkbox" + (c.getPublished()?" CHECKED>":">")+ "</td></tr>"
				+ "<tr><td></td><td><input type=submit name=UserRequest value='Edit Course'></td></tr>"
				+ "</form>"
				+ "</table>");
		return buf.toString() + Home.footer;
	}
	
}
